# -*- coding: utf-8 -*-
# cython: language_level=3
import threading

import pymysql
from dbutils.pooled_db import PooledDB  # pip install DBUtils

from config import MYSQL_DB, MYSQL_IP, MYSQL_PASSWD, MYSQL_PORT, MYSQL_USER
from utils.log import log


class SingletonMeta(type):
    _instances = {}
    _lock = threading.Lock()

    def __call__(cls, *args, **kwargs):
        with  cls._lock:
            if cls not in cls._instances:
                instance = super().__call__(*args, **kwargs)
                cls._instances[cls] = instance
        return cls._instances[cls]


class MysqlDB(metaclass=SingletonMeta):
    def __init__(self, ip=MYSQL_IP, port=MYSQL_PORT, db=MYSQL_DB, user_name=MYSQL_USER, user_pass=MYSQL_PASSWD):
        try:
            print(f'连接到{MYSQL_DB}')
            self.pool = PooledDB(creator=pymysql,
                                 mincached=1,  # 最小连接数
                                 maxcached=10,  # 池中的最大空闲连接数
                                 maxconnections=1000,  # 最大连接数
                                 blocking=True,  # 不够时阻塞连接
                                 host=ip, port=port, user=user_name, passwd=user_pass, db=db, charset='utf8mb4')
        except Exception as e:
            log.error(e)
            raise e

    def mogrify(self, sql="", args=None):
        with  self.pool.connection() as conn:
            with conn.cursor() as cursor:
                try:
                    if isinstance(args, list):
                        result = [cursor.mogrify(sql, args=i) for i in args]
                    else:
                        result = cursor.mogrify(sql, args=args)
                except Exception as e:
                    log.error(f"{(e, sql, args)}")
                else:
                    return result

    def find(self, sql, fetch_one=False, to_json=False, args=None):
        with  self.pool.connection() as conn:
            with conn.cursor() as cursor:
                try:
                    count = cursor.execute(sql, args=args)
                    if fetch_one:
                        result = cursor.fetchone()
                    else:
                        result = cursor.fetchall()
                    if to_json and result:
                        key_name = list(i[0] for i in cursor.description)
                        if fetch_one:
                            result = dict(zip(key_name, result))
                        else:
                            result = [dict(zip(key_name, i)) for i in result]
                    return result
                except Exception as e:
                    try:
                        log.error(f"{(e, cursor.mogrify(sql, args=args))}")
                    except:
                        log.error(f"{(e, sql, args)}")

    def add(self, sql, args=None, exception_callfunc=''):
        with  self.pool.connection() as conn:
            with conn.cursor() as cursor:
                try:
                    if isinstance(args, list):
                        cursor.executemany(sql, args=args)
                        mid = True
                    else:
                        cursor.execute(sql, args=args)
                        mid = cursor.lastrowid
                    conn.commit()
                except Exception as e:
                    print('----------eeeeeeee',e)
                    conn.rollback()
                    if e.args[0] != 1062:
                        try:
                            log.error(f"{(e, cursor.mogrify(sql, args=args))}")
                        except:
                            log.error(f"{(e, sql, args)}")
                    # if exception_callfunc:
                    #     exception_callfunc(e)
                    return False
                else:
                    print(mid)
                    return mid

    def update(self, sql, args=None):
        with  self.pool.connection() as conn:
            with conn.cursor() as cursor:
                try:
                    cursor.execute(sql, args=args)
                    row_count = cursor.rowcount
                    conn.commit()
                except Exception as e:
                    try:
                        log.error(f"{(e, cursor.mogrify(sql, args=args))}")
                    except:
                        log.error(f"{(e, sql, args)}")
                    conn.rollback()
                    return False
                else:
                    return row_count

    def delete(self, sql, args=None):
        with  self.pool.connection() as conn:
            with conn.cursor() as cursor:
                try:
                    cursor.execute(sql, args=args)
                    conn.commit()
                except Exception as e:
                    try:
                        log.error(f"{(e, cursor.mogrify(sql, args=args))}")
                    except:
                        log.error(f"{(e, sql, args)}")
                    conn.rollback()
                    return False
                else:
                    return True

    def set_unique_key(self, table, key):
        with  self.pool.connection() as conn:
            with conn.cursor() as cursor:
                try:
                    sql = 'alter table %s add unique (%s)' % (table, key)
                    cursor.execute(sql)
                    conn.commit()
                except Exception as e:
                    log.error(table + ' ' + str(e) + ' key = ' + key)
                else:
                    log.debug('%s表创建唯一索引成功 索引为 %s' % (table, key))

    def close(self):
        self.pool.close()


if __name__ == '__main__':
    mc = MysqlDB()
    print(mc.find('select now()'))
